﻿using System;
using System.Windows.Threading;
using System.Security.Permissions;


namespace DailyFx.UI
{
    /// <summary>
    ///		Provides a set of commonly used Dispatcher extension methods for WPF
    /// </summary>
    public static class DispatcherExtension
    {
        /// <summary>
        ///		to invoke a delegate on the correct thread .
		///		if it is not currently on the correct thread which can be used with DispatcherObject types.
        /// </summary>
        public static void InvokeIfRequired ( this Dispatcher dispatcher, Action action, DispatcherPriority priority )
        {
            if (!dispatcher.CheckAccess())
            {
                dispatcher.Invoke(priority, action);
            }
            else
            {
                action();
            }
        }

        /// <summary>
        ///		to invoke a delegate on the correct thread .
		///		if it is not currently on the correct thread which can be used with DispatcherObject types.
        /// </summary>
        public static void InvokeIfRequired ( this Dispatcher dispatcher, Action action )
        {
            if ( !dispatcher.CheckAccess() )
            {
                dispatcher.Invoke ( DispatcherPriority.Normal, action );
            }
            else
            {
                action();
            }
        }

        /// <summary>
        ///		to invoke a delegate on the correct thread in background .
		///		if it is not currently on the correct thread which can be used with DispatcherObject types.
        /// </summary>
        public static void InvokeInBackgroundIfRequired ( this Dispatcher dispatcher, Action action )
        {
            if ( !dispatcher.CheckAccess() )
            {
                dispatcher.Invoke(DispatcherPriority.Background, action);
            }
            else
            {
                action();
            }
        }

        /// <summary>
        ///		to invoke a delegate on the correct thread asynchronously .
		///		if it is not currently on the correct thread which can be used with DispatcherObject types.
        /// </summary>
        public static void InvokeAsynchronouslyInBackground ( this Dispatcher dispatcher, Action action )
        {
			if (dispatcher != null)
			{
				dispatcher.BeginInvoke(DispatcherPriority.Background, action);
			}
			else
			{
				action();
			}
        }



		/// <summary>
        ///		Forces the WPF message pump to process all enqueued messages 
		///		that are above the input priority, assume background and above by default .
        /// </summary>
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static void Pump ( DispatcherPriority priority = DispatcherPriority.Background )
        {
            DispatcherFrame frame = new DispatcherFrame();
            DispatcherOperation dispatcherOperation =
                Dispatcher.CurrentDispatcher.BeginInvoke( priority, new DispatcherOperationCallback(forceFrameExiting), frame );

            Dispatcher.PushFrame ( frame);

            if ( dispatcherOperation.Status != DispatcherOperationStatus.Completed )
            {
                dispatcherOperation.Abort ();
            }
        }



        /// <summary>
        ///     Stops the dispatcher from continuing
        /// </summary>
        private static object forceFrameExiting ( object @object )
        {
			((DispatcherFrame)@object).Continue = false;
            return null;
        }
    }

}
